package com.creator.pangu.core.global;

import com.creator.pangu.common.enums.HTTPStatusCode;
import com.creator.pangu.common.exception.CaptchaException;
import com.creator.pangu.common.exception.CaptchaExpireException;
import com.creator.pangu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常处理器
 *
 * @author Lijunjie
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 权限校验异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public R handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
        log.error("请求地址'{}',权限校验失败'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.FORBIDDEN);
    }

    /**
     * 资源无法访问
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public R handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
        log.error("请求地址'{}',访问资源不存在'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.NOT_FOUND);
    }

    /**
     * 验证码失败
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(CaptchaException.class)
    public R handleCaptchaException(CaptchaException e, HttpServletRequest request) {
        log.error("请求地址'{}',验证码失败！'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }

    /**
     * 验证码失败
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(CaptchaExpireException.class)
    public R handleCaptchaExpireException(CaptchaExpireException e, HttpServletRequest request) {
        log.error("请求地址'{}',验证码失败！'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }

    /**
     * 账户已经锁定
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(LockedException.class)
    public R handleCaptchaLockedException(LockedException e, HttpServletRequest request) {
        log.error("请求地址'{}',账户已经锁定！'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }

    /**
     * 用户名密码验证失败
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(BadCredentialsException.class)
    public R handleBadCredentialsException(BadCredentialsException e, HttpServletRequest request) {
        log.error("请求地址'{}',用户名密码错误！'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }

    /**
     * 用户名不存在
     *
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(UsernameNotFoundException.class)
    public R handleUsernameNotFoundException(UsernameNotFoundException e, HttpServletRequest request) {
        log.error("请求地址'{}',用户名不存在！'{}'", request.getRequestURI(), e.getMessage());
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        log.error("请求地址'{}',不支持'{}'请求", request.getRequestURI(), e.getMethod());
        return R.error(HTTPStatusCode.METHOD_NOT_ALLOWED);
    }

    /**
     * 0
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public R handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        log.error("请求地址'{}',发生未知异常.", request.getRequestURI(), e);
        return R.error(HTTPStatusCode.ERROR, e.getMessage());
    }


    /**
     *  违反唯一性约束
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
        log.error("请求地址'{}',发生系统异常.", request.getRequestURI(), e);
        return R.error(HTTPStatusCode.ERROR,"数据违反唯一性约束！");
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public R handleException(Exception e, HttpServletRequest request) {
        log.error("请求地址'{}',发生系统异常.", request.getRequestURI(), e);
        return R.error(HTTPStatusCode.ERROR);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public R handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return R.error(HTTPStatusCode.ERROR, message);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return R.error(HTTPStatusCode.ERROR, message);
    }

}
